package cn.yzgy.yzgyoa.common.shiro;

import cn.yzgy.yzgyoa.ucenter.constrant.UserAccountState;
import cn.yzgy.yzgyoa.ucenter.entity.SysPermission;
import cn.yzgy.yzgyoa.ucenter.entity.SysRole;
import cn.yzgy.yzgyoa.ucenter.entity.SysUser;
import cn.yzgy.yzgyoa.ucenter.service.impl.SysPermissionServiceImpl;
import cn.yzgy.yzgyoa.ucenter.service.impl.SysRoleServiceImpl;
import cn.yzgy.yzgyoa.ucenter.service.impl.SysUserServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.yzgy.yzgyoa.common.constant.SystemConstant.*;

/**
 * Shiro 用户认证类
 * @author Yqsen
 * @since 2019-8-20 16:16:26
 */
@Slf4j
@Component
public class AuthRealm extends AuthorizingRealm {

    private final SysUserServiceImpl sysUserService;

    private final SysRoleServiceImpl sysRoleService;

    private final SysPermissionServiceImpl sysPermissionService;

    public AuthRealm(SysUserServiceImpl sysUserService, SysRoleServiceImpl sysRoleService, SysPermissionServiceImpl sysPermissionService) {
        this.sysUserService = sysUserService;
        this.sysRoleService = sysRoleService;
        this.sysPermissionService = sysPermissionService;
    }


    /**
     * Shiro 授权流程
     * @param principals principals
     * @return AuthorizationInfo
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        // 授权流程：获取用户的角色、权限信息并设置到SimpleAuthorizationInfo返回

        SysUser user = (SysUser) SecurityUtils.getSubject().getPrincipal();
        log.info("Shiro -> 用户[{}]授权流程开始.", user.getLoginName());
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        // 获取用户角色列表
        Set<String> roles = sysRoleService.getRolesByUid(user.getId().toString())
                .stream().map(SysRole::getRoleName).collect(Collectors.toSet());

        // 获取用户权限列表
        Set<String> perms = sysPermissionService.getPermissionsByUid(user.getId().toString())
                .stream().map(SysPermission::getPVal).collect(Collectors.toSet());


        // 设置用户角色和权限
        simpleAuthorizationInfo.setRoles(roles);
        simpleAuthorizationInfo.setStringPermissions(perms);

        return simpleAuthorizationInfo;
    }

    /**
     * Shiro 认证流程
     * @param token token
     * @return AuthenticationInfo
     * @throws AuthenticationException 认证异常
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userName =(String)token.getPrincipal();
        log.info("Shiro -> 用户[{}]认证流程开始.",userName);
        SysUser user = sysUserService.getUserByUserName(userName);
        if (null == user) {
            log.warn("用户：{} 不存在.",userName);
            throw new UnknownAccountException();
        }
        if (UserAccountState.USER_ACCOUNT_STATE_FROZEN.getState() == user.getState()) {
            throw new LockedAccountException();
        }

        // 校验过程
        return new SimpleAuthenticationInfo(
                user,
                user.getPsw(),
                ByteSource.Util.bytes(user.getSalt()),
                getName()
        );
    }

    @Override
    public  boolean isPermitted(PrincipalCollection principals, String permission){
        AuthorizationInfo authorizationInfo1 = getAuthorizationInfo(principals);
        // 超级管理员特殊处理
        if (authorizationInfo1.getStringPermissions().size() == SIZE1 &&
                authorizationInfo1.getStringPermissions().contains(ALL_PERMISSIONS_STRING)) {
            return true;
        }
        return super.isPermitted(principals,permission);
    }

    @Override
    public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
        AuthorizationInfo authorizationInfo1 = getAuthorizationInfo(principals);
        // 超级管理员特殊处理
        if (authorizationInfo1.getRoles().size() == SIZE1 &&
                authorizationInfo1.getRoles().contains(SUPER_ADMIN_ROLE_STRING)) {
            return true;
        }
        return super.hasRole(principals,roleIdentifier);
    }

    /**
     * 获取当前用户的全部权限信息
     * @return permissions
     */
    public Set<String> getPermissions(){
        return new HashSet<>(getAuthorizationInfo(SecurityUtils.getSubject().getPrincipals()).getStringPermissions());
    }

}
